package com.lag.transfer.servlet;

import com.lag.transfer.annotation.MyDefinedAutowired;
import com.lag.transfer.annotation.MyDefinedRepository;
import com.lag.transfer.annotation.MyDefinedService;
import com.lag.transfer.factory.BeanFactory;
import com.lag.transfer.factory.ProxyFactory;
import com.lag.transfer.pojo.Result;
import com.lag.transfer.service.TransferService;
import com.lag.transfer.utils.ConnectionUtils;
import com.lag.transfer.utils.JsonUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author June
 * @since 2020年12月
 */
@WebServlet(name = "transferServlet", urlPatterns = "/transferServlet")
public class TransferServlet extends HttpServlet {

    private static String scannPackage = "com.lag.transfer";

    private List<String> classNames = new ArrayList<>();

    private Map<String, Object> ioc = new HashMap<>();


    @Autowired
    private TransferService transferService;

    @Override
    public void init() throws ServletException {
        // WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        // transferService = (TransferService) webApplicationContext.getBean("transferService");

        // 1.根据properties，初始化所有相关联的类,扫描用户设定的包下面所有的类
        doScanner(scannPackage);

        // 2.拿到扫描到的类,通过反射机制,实例化,并且放到ioc容器中(k-v  beanName-bean) beanName默认是首字母小写
        doInstance();

        // 3.自动化注入依赖
        doAutowired();

        ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
        transferService = (TransferService) proxyFactory.getJDKProxy(ioc.get("transferService")) ;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 设置请求体的字符编码
        req.setCharacterEncoding("UTF-8");

        String fromCardNo = req.getParameter("fromCardNo");
        String toCardNo = req.getParameter("toCardNo");
        String moneyStr = req.getParameter("money");
        int money = Integer.parseInt(moneyStr);

        Result result = new Result();
        try {
            // 2. 调用service层方法
            transferService.transfer(fromCardNo, toCardNo, money);
            result.setStatus("200");
        } catch (Exception e) {
            e.printStackTrace();
            result.setStatus("201");
            result.setMessage(e.toString());
        }
        // 响应
        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().print(JsonUtils.object2Json(result));
    }

    private void doScanner(String packageName) {
        URL url = this.getClass().getResource("/" + packageName.replaceAll("\\.", "/"));
        File dir = new File(url.getFile());
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                doScanner(packageName + "." + file.getName());
            } else {
                String className = packageName + "." + file.getName().replace(".class", "");
                classNames.add(className);
            }
        }
    }

    private void doInstance() {
        if (classNames.isEmpty()) {
            return;
        }
        for (String className : classNames) {
            try {
                //把类搞出来,反射来实例化(只有加@MyController需要实例化)
                Class<?> clazz = Class.forName(className);
                if (clazz.isAnnotationPresent(MyDefinedService.class)) {
                    MyDefinedService myService = clazz.getAnnotation(MyDefinedService.class);
                    ioc.put(myService.value(), clazz.newInstance());
                } else if (clazz.isAnnotationPresent(MyDefinedRepository.class)) {
                    MyDefinedRepository myService = clazz.getAnnotation(MyDefinedRepository.class);
                    String beanName = myService.value();
                    if ("".equals(beanName.trim())) {
                        beanName = toLowerFirstWord(clazz.getSimpleName());
                    }
                    Object instance = clazz.newInstance();
                    ioc.put(beanName, instance);
                    Class[] interfaces = clazz.getInterfaces();
                    for (Class<?> i : interfaces) {
                        ioc.put(i.getName(), instance);
                    }
                    ConnectionUtils connectionUtils = (ConnectionUtils) BeanFactory.getBean("connectionUtils");
                    ioc.put("connectionUtils", connectionUtils);
                } else {
                    continue;
                }
            } catch (Exception e) {
                e.printStackTrace();
                continue;
            }
        }
    }

    private void doAutowired(){

        if (ioc.isEmpty()){
            return;
        }
        for (Map.Entry<String,Object> entry:ioc.entrySet()){
            //包括私有的方法，在spring中没有隐私，@MyAutowired可以注入public、private字段
            Field[] fields=entry.getValue().getClass().getDeclaredFields();
            for (Field field:fields){
                if (!field.isAnnotationPresent(MyDefinedAutowired.class)){
                    continue;
                }
                MyDefinedAutowired autowired= field.getAnnotation(MyDefinedAutowired.class);
                String beanName=autowired.value().trim();
                if ("".equals(beanName)){
                    beanName=field.getType().getName();
                }
                field.setAccessible(true);
                try {
                    field.set(entry.getValue(),ioc.get(beanName));
                }catch (Exception e){
                    e.printStackTrace();
                    continue;
                }

            }
        }
    }

    private String toLowerFirstWord(String name){
        char[] charArray = name.toCharArray();
        charArray[0] += 32;
        return String.valueOf(charArray);
    }
}
